进程与线程
借鉴维基百科中的解释:
进程
进程(Process),是计算机中已运行程序的实体。
在面向进程设计的系统,进程是程序的基本执行实体;而在面向线程设计的系统(当今多数操作系统)中,进程本身不是基本运行单位,而是线程的容器。
程序本身只是指令、数据及其组织形式的描述,进程才是程序(指令和数据)的真正运行实例。
若干进程有可能与同一个程序相关系,且每个进程皆可以同步或异步的方式独立运行。
现代计算机系统可在同一时段时间内以进程的形式将多个程序加载到内存中,并借由时间共享,以在一个处理器上表现出同时运行的感觉。
使用多线程技术的操作系统或计算机结构,同样程序的平行线程,可在多CPU主机或网络上真正同时运行。
线程
线程(Thread),是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运行单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。
一个进程可以有很多线程,每条线程并行执行不同的任务。
在多核或多CPU,或支持Hyper-threading的CPU上使用多线程程序设计的好处是显而易见,即提高了程序的执行吞吐率。在单CPU单核的计算机上,使用多线程技术,也可以把进程中负责IO处理、人机交互而常被阻塞的部分与密集计算的部分分开来执行,编写专门的workhorse线程执行密集计算,从而提高了程序的执行效率。
自定义 Java 线程
在 Java 的 JDK 开发包中,已经自带了对多线程技术的支持,可以很方便地进行多线程编程。实现多线程编程的方式主要有两种:
- 继承 Thread 类
- 实现 Runnable 接口
继承 Thread 类
Java 提供 Thread 类,自定义线程只需要继承自 Thread ,并且重写 run 方法即可:1
2
3
4
5
6
7
8
9public class CustomThread extends Thread {
public void run() {
super.run();
System.out.printf("通过继承 Thread 类自定义线程");
}
}
使用自定义的线程类:1
2
3
4
5
6
7
8public class CustomThreadTest {
public static void main(String[] args) {
CustomThread customThread = new CustomThread();
customThread.start();
System.out.println("运行自定义线程结束");
}
}
实现 Runnable 接口
Java 提供 Runnable 接口,自定义线程只需要实现 Runnable ,并且实现 run 方法即可:1
2
3
4
5
6public class CustomRunnable implements Runnable {
public void run() {
System.out.printf("通过实现 Runnable 接口自定义线程");
}
}
使用自定义的线程类:1
2
3
4
5
6
7
8
9public class CustomRunnableTest {
public static void main(String[] args) {
CustomRunnable customRunnable = new CustomRunnable();
Thread thread = new Thread(customRunnable);
thread.start();
System.out.println("运行自定义线程结束");
}
}
两者在使用时有些许差别,通过实现 Runnable 接口的线程类使用时需要通过 Thread 类。而通过继承 Thread 类的线程类使用时不需要通过 Thread 类。
因为 Thread 已经实现了 Runnable 接口:1
public class Thread implements Runnable
Thread 类有两个常用的构造函数:1
2
3
4
5
6
7
8 public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
其分别对应了上述两种情形。
因为 Java 单继承的局限性,在实际使用中,优先推荐通过实现 Runnable 接口自定义线程。
线程运行随机性
运行上述自定义线程,其输出结果可能是:1
2运行自定义线程结束
自定义线程
可能是:1
2自定义线程
运行自定义线程结束
一个线程的运行依赖其被其他线程调用 start()方法,start() 方法调用线程内的 run() 方法(如果直接调用 run() 方法其和普通的 Java 类没有任何区别)。Java 应用程序最少也会有一个运行 main() 方法的线程,称为主线程。
上述运行结果中: “运行自定义线程结束”即主线程调用执行 main() 方法后,main() 方法输出的信息,”自定义线程”即主线程调用自定义线程的 start() 方法后,自定义线程 start() 方法调用其 run() 方法后,run() 方法输出的信息。
之所以出现上述情况,是因为线程作为操作系统运行的最小单位,CPU 以分时共享的方式调用,其调用是不确定的。